package androidgame.framework.gl;

import java.nio.ByteBuffer;

import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

import androidgame.framework.impl.GLGraphics;

// Helper class to deal with vertices and drawing textures. 
// Texture coordinates are top-left origin.
// @author dicarlo2

public class Vertices {
	final GLGraphics glGraphics;
	final boolean hasColor;
	final boolean hasTexCoords;
	final int vertexSize;
	final IntBuffer vertices;
	final int[] tmpBuffer;
	final ShortBuffer indices;

	// The constructor specifies how many vertices and indices the Vertices
	// instance can maximally hold.
	// Defines where the vertices has texture coordinates or colors associated
	// as well.

	public Vertices(GLGraphics glGraphics, int maxVertices, int maxIndices,
			boolean hasColor, boolean hasTexCoords) {
		this.glGraphics = glGraphics;
		this.hasColor = hasColor;
		this.hasTexCoords = hasTexCoords;
		this.vertexSize = (2 + (hasColor ? 4 : 0) + (hasTexCoords ? 2 : 0)) * 4;
		this.tmpBuffer = new int[maxVertices * vertexSize / 4];

		ByteBuffer buffer = ByteBuffer.allocateDirect(maxVertices * vertexSize);
		buffer.order(ByteOrder.nativeOrder());
		vertices = buffer.asIntBuffer();

		if (maxIndices > 0) {
			buffer = ByteBuffer.allocateDirect(maxIndices * Short.SIZE / 8);
			buffer.order(ByteOrder.nativeOrder());
			indices = buffer.asShortBuffer();
		} else {
			indices = null;
		}
	}

	// Sets the vertices of the instance. The input array must take care to
	// account for if the Vertices instance
	// is set for texCoords and/or colorCoords.

	public void setVertices(float[] vertices, int offset, int length) {
		this.vertices.clear();
		int len = offset + length;
		for (int i = offset, j = 0; i < len; i++, j++)
			tmpBuffer[j] = Float.floatToRawIntBits(vertices[i]);
		this.vertices.put(tmpBuffer, 0, length);
		this.vertices.flip();
	}

	// Sets the indices for the vertices of the instance. Like above, the input
	// array must take care to account for
	// if the Vertices instance is set for texCoords and/or colorCoords.

	public void setIndices(short[] indices, int offset, int length) {
		this.indices.clear();
		this.indices.put(indices, offset, length);
		this.indices.flip();
	}
	
	// Sets the GL10 instance to be prepared to draw the vertices.

	public void bind() {
		GL10 gl = glGraphics.getGL();

		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		vertices.position(0);
		gl.glVertexPointer(2, GL10.GL_FLOAT, vertexSize, vertices);

		if (hasColor) {
			gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
			vertices.position(2);
			gl.glColorPointer(4, GL10.GL_FLOAT, vertexSize, vertices);
		}

		if (hasTexCoords) {
			gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			vertices.position(hasColor ? 6 : 2);
			gl.glTexCoordPointer(2, GL10.GL_FLOAT, vertexSize, vertices);
		}
	}
	
	// Draws the vertices. **** bind() MUST be called first, and then unbind() MUST be called when drawing of 
	// these vertices is completed. This allows for the same object to be drawn multiple times without 
	// overloading the hardware by binding and unbinding over and over. ****

	public void draw(int primitiveType, int offset, int numVertices) {
		GL10 gl = glGraphics.getGL();

		if (indices != null) {
			indices.position(offset);
			gl.glDrawElements(primitiveType, numVertices,
					GL10.GL_UNSIGNED_SHORT, indices);
		} else {
			gl.glDrawArrays(primitiveType, offset, numVertices);
		}
	}

	public void unbind() {
		GL10 gl = glGraphics.getGL();
		if (hasTexCoords)
			gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

		if (hasColor)
			gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
	}
}
